package org.wk.account.service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.wk.account.dao.SubAccountDao;
import org.wk.account.dao.zuan.*;
import org.wk.account.domain.SubAccount;
import org.wk.account.domain.bao.SubAccountBaoSeq;
import org.wk.account.domain.ling.SubAccountLing;
import org.wk.account.domain.ling.SubAccountLingExchangeCNY;
import org.wk.account.domain.ling.SubAccountLingExchangeCNYBill;
import org.wk.account.domain.ling.SubAccountLingSeq;
import org.wk.account.domain.zuan.*;
import org.wk.account.enums.*;
import org.wk.account.view.ConfigVo;
import org.wk.account.view.ZuanExchangeCNYVo;
import org.wk.common.dao.SmsDao;
import org.wk.common.domain.Sms;
import org.wk.common.enums.SmsCodeType;
import org.wk.common.jpush.PushService;
import org.wk.core.common.tool.RegexUtils;
import org.wk.core.common.view.PageVo;
import org.wk.core.common.view.ResponseVo;
import org.wk.core.db.tool.WebUtils;
import org.wk.core.web.exception.GeneralException;
import org.wk.user.enums.IdentityType;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;


@Service
public class SubAccountZuanServiceImpl implements SubAccountZuanService {

	private final Logger logger = LoggerFactory.getLogger(this.getClass()); 
	
	@Autowired
	private SubAccountDao subAccountDao;
	@Autowired
	private SubAccountZuanDao subAccountZuanDao;
	@Autowired
	private SubAccountZuanSeqDao subAccountZuanSeqDao;
	@Autowired
	private SubAccountZuanRegistBillDao subAccountZuanRegistBillDao;
	@Autowired
	private SubAccountZuanAttendancesBillDao subAccountZuanAttendancesBillDao;
	@Autowired
	private SubAccountZuanExchangeCNYDao zuanExchangeCNYDao;
	@Autowired
	private SubAccountZuanAdminUpdateBillDao subAccountZuanAdminUpdateBillDao;

	@Autowired
	private ConfigService configService;

	@Autowired
	private SmsDao smsDao;

	@Autowired
	private PushService pushService;


	@Override
	public boolean registerAward(String userId) {
		// TODO Auto-generated method stub
		logger.info("注册奖励鲸钻");
		ConfigVo configVo = configService.selectByCode(TransferConfig.zuan_register_num.getCode());
		if (configVo==null || Strings.isNullOrEmpty(configVo.getConfigValue())) {
			logger.info("未设置注册奖励");
			return true;
		}
		int num = Integer.valueOf(configVo.getConfigValue());
		if (num<=0) {
			return true;
		}
		ZuanChangeType zuanChangeType = ZuanChangeType.register;
		
		//保存注册奖励鲸钻记录
		SubAccountZuanRegistBill subAccountZuanRegistBill = new SubAccountZuanRegistBill();
		subAccountZuanRegistBill.setUserId(userId);
		subAccountZuanRegistBill.setAmount(num);
		subAccountZuanRegistBillDao.save(subAccountZuanRegistBill);
		//保存鲸钻账户记录
		return accountZuanSeqHandler(userId, zuanChangeType, SeqFlag.INCOME, num);
	}

	@Override
	public boolean loginAward(String userId) {
		// TODO Auto-generated method stub
		//每天首次登录奖励鲸钻 只奖励一次
//		SubAccountZuanLoginBill subAccountZuanLoginBill = subAccountZuanLoginBillDao.findByUserIdAndDay(userId,new DateTime().toString("yyyy-MM-dd"));
//		if (subAccountZuanLoginBill==null) {
//			logger.info("每日首次登录奖励鲸钻");
//			ZuanChangeType zuanChangeType = ZuanChangeType.login;
//			subAccountZuanLoginBill = new SubAccountZuanLoginBill();
//			subAccountZuanLoginBill.setUserId(userId);
//			subAccountZuanLoginBill.setAmount(zuanChangeType.getNumber());
//			subAccountZuanLoginBillDao.save(subAccountZuanLoginBill);
//			return accountZuanSeqHandler(userId, zuanChangeType, SeqFlag.INCOME);
//		}
		return true;
	}

	@Override
	public boolean promoteAward(String userId) {
		// TODO Auto-generated method stub
		logger.info("推广奖励鲸钻");
		ConfigVo configVo = configService.selectByCode(TransferConfig.zuan_promote_num.getCode());
		if (configVo==null || Strings.isNullOrEmpty(configVo.getConfigValue())) {
			logger.info("未设置推广奖励");
			return true;
		}
		int num = Integer.valueOf(configVo.getConfigValue());
		if (num<=0) {
			return true;
		}
		ZuanChangeType zuanChangeType = ZuanChangeType.promote;
		
		//保存注册奖励鲸钻记录
		SubAccountZuanRegistBill subAccountZuanRegistBill = new SubAccountZuanRegistBill();
		subAccountZuanRegistBill.setUserId(userId);
		subAccountZuanRegistBill.setAmount(num);
		subAccountZuanRegistBillDao.save(subAccountZuanRegistBill);
		//保存鲸钻账户记录
		return accountZuanSeqHandler(userId, zuanChangeType, SeqFlag.INCOME, num);
	}

	/**
	 * 鲸钻变动记录处理
	 * @param userId 用户ID
	 * @param zuanChangeType 变动类型
	 * @param seqFlag 变动标识
	 * @param num 变动数量
	 * @return
	 */
	private boolean accountZuanSeqHandler(String userId, ZuanChangeType zuanChangeType, SeqFlag seqFlag, int num) {
		//保存鲸钻账户记录
		SubAccountZuan subAccountZuan = subAccountZuanDao.findByUserId(userId);
		subAccountZuan = subAccountZuan==null?new SubAccountZuan():subAccountZuan;
		int preAmount = subAccountZuan.getAmount();
		subAccountZuan.setUserId(userId);
		subAccountZuan.setAmount(preAmount+num);
		subAccountZuanDao.saveOrUpdate(subAccountZuan);
		//保存鲸钻账户变动记录
		SubAccountZuanSeq subAccountZuanSeq = new SubAccountZuanSeq();
		subAccountZuanSeq.setUserId(userId);
		subAccountZuanSeq.setSeqFlagCode(seqFlag.getCode());
		subAccountZuanSeq.setSeqFlagName(seqFlag.getName());
		subAccountZuanSeq.setChangeTypeCode(zuanChangeType.getCode());
		subAccountZuanSeq.setChangeTypeName(zuanChangeType.getName());
		
		subAccountZuanSeq.setPreAmount(preAmount);
		subAccountZuanSeq.setAmount(subAccountZuan.getAmount());
		subAccountZuanSeq.setChangeAmount(num);
		
		subAccountZuanSeqDao.save(subAccountZuanSeq);
		
		//保存用户账户中鲸钻账户记录
		SubAccount subAccount = subAccountDao.findByUserIdAndAccountTypeCode(userId,AccountType.JING_ZUAN.getCode());
		
		subAccount.setAmount(new BigDecimal(subAccountZuan.getAmount()));
		subAccountDao.update(subAccount);
		
		return true;
	}

	@Override
	public Page<SubAccountZuanSeq> findSeqByCriteria(Integer page, Integer size, SubAccountZuanSeq subAccountZuanSeq) {
		Sort sort = Sort.by(Sort.Direction.DESC,"createTime");
		Page<SubAccountZuanSeq> zuanSeqPage = subAccountZuanSeqDao.findAll(new Specification<SubAccountZuanSeq>() {
			@Override
			public Predicate toPredicate(Root<SubAccountZuanSeq> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {

				List<Predicate> list = new ArrayList<Predicate>();
				if(null!=subAccountZuanSeq.getUserId()&&!"".equals(subAccountZuanSeq.getUserId())){
					list.add(criteriaBuilder.equal(root.get("userId").as(String.class), subAccountZuanSeq.getUserId()));
				}
				Predicate[] p = new Predicate[list.size()];
				return criteriaBuilder.and(list.toArray(p));
			}
		}, PageRequest.of(page,size,sort));
		return zuanSeqPage;
	}

	/*
	 * @Description 每日签到奖励鲸钻
	 * @Param [userId]
	 * @author ZhaoPing'an
	 * @Date 2018/5/21 17:30
	 */
	@Override
	public boolean attendancesAward(String userId) {
		logger.info("每日签到奖励鲸钻");

		ConfigVo configVo = configService.selectByCode(TransferConfig.zuan_attendances_num.getCode());
		if (configVo==null || Strings.isNullOrEmpty(configVo.getConfigValue())) {
			logger.info("未设置注册奖励");
			return true;
		}
		int num = Integer.valueOf(configVo.getConfigValue());
		if (num<=0) {
			return true;
		}

		ZuanChangeType zuanChangeType = ZuanChangeType.attendances;

		//保存奖励鲸钻记录
		SubAccountZuanAttendancesBill subAccountZuanAttendancesBill = new SubAccountZuanAttendancesBill();
		subAccountZuanAttendancesBill.setUserId(userId);
		subAccountZuanAttendancesBill.setAmount(num);
		subAccountZuanAttendancesBillDao.save(subAccountZuanAttendancesBill);
		//保存鲸钻账户记录
		return accountZuanSeqHandler(userId, zuanChangeType, SeqFlag.INCOME, num);
	}

	/*
	 * @Description 鲸钻提取现金服务
	 * @param
	 * @author ZhaoPing'an
	 * @Date 2018/7/2 15:25
	 */
	@Override
	public ResponseVo zuanExchangeCNY(JSONObject jsonObject) {
		String exchangecnyTypeCode = jsonObject.getString("exchangecnyTypeCode");
		// 真实姓名
		String realName = jsonObject.getString("real_name");
		// 收款账户（支付宝、银行卡？）
		String receiveAccount = jsonObject.getString("receive_account");
		// 提现金额
		int quantity = jsonObject.getIntValue("quantity");
		// 手机号
		String mobileNumber = jsonObject.getString("mobile_number");
		String smsCode = jsonObject.getString("sms_code");
		String userId = WebUtils.getUser().getId();
		SubAccountZuan subAccountZuan = subAccountZuanDao.findByUserId(userId);
		// 当前账户鲸灵金额
		int preAmount = subAccountZuan.getAmount();
		// 数据校验
		if(Strings.isNullOrEmpty(exchangecnyTypeCode) || Strings.isNullOrEmpty(realName) || Strings.isNullOrEmpty(receiveAccount)
				|| quantity==0 || Strings.isNullOrEmpty(smsCode)) {
			return new ResponseVo(ResponseCode.COMPLETE_DATA);
		}
		// 手机号校验
		if (Strings.isNullOrEmpty(mobileNumber)||!RegexUtils.checkMobileNum(mobileNumber)) {
			return new ResponseVo(ResponseCode.MOBILE_NUMBER_ERROR);
		}
		// 验证码校验
		Sms sms = smsDao.findByMobileNumberAndSmsCodeTypeGreaterThanExpireTimeLimit1(mobileNumber,SmsCodeType.EXCHANGE_CNY.getCode(),new Date());
		if (null == sms || !smsCode.equals(sms.getSmsCode())) {
			return new ResponseVo(ResponseCode.SMS_CODE_ERROR);
		}
		// 判断用户身份是否为VIP
		if (!WebUtils.getUser().getData().get("identityCode").equals(IdentityType.AVERAGE.getCode())){
			return new ResponseVo(ResponseCode.NOT_VIP);
		}
		// 用户鲸钻余额与数量校验（200的整数倍）
		if (quantity < 200||quantity%200!=0){
			return new ResponseVo(ResponseCode.DATA_ERROR);
		}
		// 当前鲸钻账户余额校验
		if (quantity>preAmount){
			return new ResponseVo(ResponseCode.AMOUNT_DATA_ERROR);
		}
		// 扣除20%手续费，兑换比例2:1（可配置？）
		int amountCNY = (quantity - quantity*2/10)/2;
		// 保存提现账单流水
		SubAccountZuanExchangeCNY subAccountZuanExchangeCNY = new SubAccountZuanExchangeCNY();
		subAccountZuanExchangeCNY.setUserId(userId);
		subAccountZuanExchangeCNY.setAmount(amountCNY);
		subAccountZuanExchangeCNY.setZuanAmount(quantity);
		subAccountZuanExchangeCNY.setRealName(realName);
		subAccountZuanExchangeCNY.setMobileNumber(mobileNumber);
		subAccountZuanExchangeCNY.setReceiveAccount(receiveAccount);
		subAccountZuanExchangeCNY.setExchangecnyTypeCode(ExchangeCNYType.ALIPAY.getCode());
		subAccountZuanExchangeCNY.setExchangecnyTypeName(ExchangeCNYType.ALIPAY.getName());
		subAccountZuanExchangeCNY.setExchangeStatusCode(ExchangeCNYStatus.NOT_EXCHANGE_CNY.getCode());
		subAccountZuanExchangeCNY.setExchangeStatusName(ExchangeCNYStatus.NOT_EXCHANGE_CNY.getName());
		zuanExchangeCNYDao.save(subAccountZuanExchangeCNY);
		return ResponseVo.success();
	}

	/*
	 * @Description PC鲸钻提现列表
	 * @param
	 * @author ZhaoPing'an
	 * @Date 2018/7/3 16:21
	 */
	@Override
	public PageVo findExchangeCNYListPage(Map<String, Object> params) {
		String keyword = (String)params.get("keyword");
		String temp = (String)params.get("page");
		Integer pageNo = temp==null?0:Integer.parseInt(temp)-1;
		temp = (String) params.get("limit");
		Integer pageSize = temp==null?10:Integer.parseInt(temp);
		SubAccountZuanExchangeCNY zuanExchangeCNY = new SubAccountZuanExchangeCNY();
		zuanExchangeCNY.setMobileNumber(keyword);
		Page<SubAccountZuanExchangeCNY> page = zuanExchangeCNYDao.findAll(new Specification<SubAccountZuanExchangeCNY>() {
			@Override
			public Predicate toPredicate(Root<SubAccountZuanExchangeCNY> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
				List<Predicate> list = new ArrayList<Predicate>();
				if(null!=zuanExchangeCNY.getMobileNumber()&&!"".equals(zuanExchangeCNY.getMobileNumber())){
					// 关键字条件查询
					list.add(criteriaBuilder.or(criteriaBuilder.like(root.get("mobileNumber").as(String.class), "%"+zuanExchangeCNY.getMobileNumber()+"%"),
							criteriaBuilder.like(root.get("realName").as(String.class), "%"+zuanExchangeCNY.getMobileNumber()+"%")));
				}
				Predicate[] p = new Predicate[list.size()];
				return criteriaBuilder.and(list.toArray(p));
			}
		}, PageRequest.of(pageNo,pageSize,new Sort(Sort.Direction.DESC,"createTime")));

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		List<ZuanExchangeCNYVo> result = new ArrayList<>();
		for (SubAccountZuanExchangeCNY subAccountZuanExchangeCNY: page.getContent() ) {
			ZuanExchangeCNYVo lingExchangeCNYVo = new ZuanExchangeCNYVo();
			BeanUtils.copyProperties(subAccountZuanExchangeCNY, lingExchangeCNYVo);
			lingExchangeCNYVo.setCreateTime(sdf.format(subAccountZuanExchangeCNY.getCreateTime()));
			result.add(lingExchangeCNYVo);
		}
		PageVo pageVo = new PageVo<ZuanExchangeCNYVo>();
		pageVo.setTotal(page.getTotalElements());
		pageVo.setPageNo(++pageNo);
		pageVo.setPageSize(pageSize);
		pageVo.setResult(result);
		pageVo.setTotalPages(page.getTotalPages());
		return pageVo;
	}

	/*
	 * @Description 鲸钻提现成功
	 * @param
	 * @author ZhaoPing'an
	 * @Date 2018/7/3 16:32
	 */
	@Override
	public ResponseVo successExchangeCNY(String id) {
		SubAccountZuanExchangeCNY entity =  zuanExchangeCNYDao.getOne(id);
		entity.setExchangeStatusCode(ExchangeCNYStatus.HAS_EXCHANGE_CNY.getCode());
		entity.setExchangeStatusName(ExchangeCNYStatus.HAS_EXCHANGE_CNY.getName());
		zuanExchangeCNYDao.update(entity);

		String userId =  entity.getUserId();
		SubAccountZuan subAccountZuan = subAccountZuanDao.findByUserId(userId);
		// 当前账户鲸灵金额
		int preAmount = subAccountZuan.getAmount();
		// 变动后金额
		int afterExchangeAmount = preAmount - entity.getAmount();
		// 更新鲸灵账户金额
		subAccountZuan.setAmount(afterExchangeAmount);
		subAccountZuan.setUserId(userId);
		subAccountZuanDao.saveOrUpdate(subAccountZuan);
		// 保存鲸灵变动记录
		SubAccountZuanSeq subAccountZuanSeq = new SubAccountZuanSeq();
		subAccountZuanSeq.setUserId(userId);
		subAccountZuanSeq.setAmount(afterExchangeAmount);
		subAccountZuanSeq.setPreAmount(preAmount);
		subAccountZuanSeq.setChangeAmount(entity.getAmount());
		subAccountZuanSeq.setSeqFlagCode(SeqFlag.EXPEND.getCode());
		subAccountZuanSeq.setSeqFlagName(SeqFlag.EXPEND.getName());
		subAccountZuanSeq.setChangeTypeCode(LingChangeType.EXCHANGE_CNY.getCode());
		subAccountZuanSeq.setChangeTypeName(LingChangeType.EXCHANGE_CNY.getName());
		subAccountZuanSeqDao.save(subAccountZuanSeq);
		// 更新用户总账户鲸灵金额
		SubAccount subAccount = subAccountDao.findByUserIdAndAccountTypeCode(userId,AccountType.JING_LING.getCode());
		subAccount.setAmount(new BigDecimal(afterExchangeAmount));
		subAccountDao.update(subAccount);

		Map<String,String> pushExt = new HashMap<>();
		pushExt.put("content_type","sys_notice");
		Map<String,Object> content = new HashMap<>();
		content.put("title","系统通知");
		content.put("content","你好，您的鲸钻提现已经成功！");
		pushExt.put("content",JSONObject.toJSONString(content));
		pushService.pushNotification("提现成功",pushExt,userId);
		return ResponseVo.success();
	}

	/**
	 * @Description 鲸钻提现拒绝
	 * @param
	 * @author ZhaoPing'an
	 * @Date 2018/7/3 16:32
	 */
	@Override
	public ResponseVo refuseExchangeCNY(ZuanExchangeCNYVo zuanExchangeCNYVo) {
		SubAccountZuanExchangeCNY entity = zuanExchangeCNYDao.getOne(zuanExchangeCNYVo.getId());
		entity.setExchangeStatusCode(ExchangeCNYStatus.REFUSE_EXCHANGE_CNY.getCode());
		entity.setExchangeStatusName(ExchangeCNYStatus.REFUSE_EXCHANGE_CNY.getName());
		entity.setReason(zuanExchangeCNYVo.getReason());
		zuanExchangeCNYDao.update(entity);
		// 通知
		Map<String,String> pushExt = new HashMap<>();
		pushExt.put("content_type","sys_notice");
		Map<String,Object> content = new HashMap<>();
		content.put("title","系统通知");
		content.put("content","你好，您的鲸钻提现失败，原因："+zuanExchangeCNYVo.getReason());
		pushExt.put("content",JSONObject.toJSONString(content));
		pushService.pushNotification("提现失败",pushExt,entity.getUserId());
		return ResponseVo.success();
	}

	@Override
	public void updateZuanAccount(BigDecimal zuan, String userId) {
		SubAccountZuan subAccountZuan = subAccountZuanDao.findByUserId(userId);
		SubAccountZuanSeq subAccountZuanSeq = new SubAccountZuanSeq();
		BigDecimal amount = new BigDecimal(subAccountZuan.getAmount());
		BigDecimal changeAmount = new BigDecimal(0);
		int num = zuan.compareTo(amount);
		if (num < 0){
			changeAmount = amount.subtract(zuan);
			subAccountZuanSeq.setSeqFlagCode(SeqFlag.EXPEND.getCode());
			subAccountZuanSeq.setSeqFlagName(SeqFlag.EXPEND.getName());
		}
		if (num > 0){
			changeAmount = zuan.subtract(amount);
			subAccountZuanSeq.setSeqFlagCode(SeqFlag.INCOME.getCode());
			subAccountZuanSeq.setSeqFlagName(SeqFlag.INCOME.getName());
		}
		if (num!=0 && zuan.compareTo(new BigDecimal(0))>=0){
			SubAccountZuanAdminUpdateBill adminUpdateBill = new SubAccountZuanAdminUpdateBill();
			adminUpdateBill.setAmount(changeAmount.intValue());
			adminUpdateBill.setUserId(userId);
			subAccountZuanAdminUpdateBillDao.save(adminUpdateBill);
			subAccountZuan.setAmount(zuan.intValue());
			subAccountZuan.setUserId(userId);
			subAccountZuanDao.saveOrUpdate(subAccountZuan);
			subAccountZuanSeq.setUserId(userId);
			subAccountZuanSeq.setChangeTypeCode(BaoChangeType.ADMIN_UPDATE.getCode());
			subAccountZuanSeq.setChangeTypeName(BaoChangeType.ADMIN_UPDATE.getName());
			subAccountZuanSeq.setPreAmount(amount.intValue());
			subAccountZuanSeq.setAmount(zuan.intValue());
			subAccountZuanSeq.setChangeAmount(changeAmount.intValue());
			subAccountZuanSeqDao.save(subAccountZuanSeq);
			SubAccount subAccount = subAccountDao.findByUserIdAndAccountTypeCode(userId, AccountType.JING_ZUAN.getCode());
			subAccount.setAmount(zuan);
			subAccountDao.update(subAccount);
		}
	}

	@Override
	public Page<SubAccountZuanSeq> findSeqByUserIds(int pageNum, int pageSize, List<String> userIds) {
		Sort sort = Sort.by(Sort.Direction.DESC,"createTime");
		Page<SubAccountZuanSeq> zuanSeqPage = subAccountZuanSeqDao.findAll(new Specification<SubAccountZuanSeq>() {
			@Override
			public Predicate toPredicate(Root<SubAccountZuanSeq> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
				List<Predicate> list = new ArrayList<Predicate>();
				if(!userIds.isEmpty()){
					CriteriaBuilder.In<String> in = criteriaBuilder.in(root.get("userId"));
					for (String userId:userIds){
						in.value(userId);
					}
					list.add(in);
				}
				Predicate[] p = new Predicate[list.size()];
				return criteriaBuilder.and(list.toArray(p));
			}
		}, PageRequest.of(pageNum,pageSize,sort));
		return zuanSeqPage;
	}
}
